<!DOCTYPE html>
<html lang="en" color-mode="light">

  <head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1" />
  <meta name="keywords" content="JavaScript,Hexo" />
  <meta name="author" content="超能虾米" />
  <meta name="description" content="" />
  
  
  <title>
    
      JUC笔记 
      
      
      |
    
     超能虾米的博客
  </title>

  
    <link rel="apple-touch-icon" href="/images/favicon.png">
    <link rel="icon" href="/images/favicon.png">
  

  <!-- Raleway-Font -->
  <link href="https://fonts.googleapis.com/css?family=Raleway&display=swap" rel="stylesheet">

  <!-- hexo site css -->
  <link rel="stylesheet" href="/css/main.css" />
  <link rel="stylesheet" href="//at.alicdn.com/t/font_1886449_67xjft27j1l.css" />
  <!-- 代码块风格 -->
  

  <!-- jquery3.3.1 -->
  
    <script defer type="text/javascript" src="/plugins/jquery.min.js"></script>
  

  <!-- fancybox -->
  
    <link href="/plugins/jquery.fancybox.min.css" rel="stylesheet">
    <script defer type="text/javascript" src="/plugins/jquery.fancybox.min.js"></script>
  
  
<script src="/js/fancybox.js"></script>


  

  

  <script>
    var html = document.documentElement
    const colorMode = localStorage.getItem('color-mode')
    if (colorMode) {
      document.documentElement.setAttribute('color-mode', colorMode)
    }
  </script>
<meta name="generator" content="Hexo 5.4.2"><link rel="alternate" href="/atom.xml" title="超能虾米的博客" type="application/atom+xml">
</head>


  <body>
    <div id="app">
      <div class="header">
  <div class="avatar">
    <a href="/">
      <!-- 头像取消懒加载，添加no-lazy -->
      
        <img src="/images/头像.JPEG" alt="">
      
    </a>
    <div class="nickname"><a href="/">超能虾米</a></div>
  </div>
  <div class="navbar">
    <ul>
      
        <li class="nav-item" data-path="/">
          <a href="/">主页</a>
        </li>
      
        <li class="nav-item" data-path="/archives/">
          <a href="/archives/">归档</a>
        </li>
      
        <li class="nav-item" data-path="/categories/">
          <a href="/categories/">分类</a>
        </li>
      
        <li class="nav-item" data-path="/tags/">
          <a href="/tags/">标签</a>
        </li>
      
        <li class="nav-item" data-path="/friends/">
          <a href="/friends/">朋友</a>
        </li>
      
        <li class="nav-item" data-path="/about/">
          <a href="/about/">关于我</a>
        </li>
      
    </ul>
  </div>
</div>


<script src="/js/activeNav.js"></script>



      <div class="flex-container">
        <!-- 文章详情页，展示文章具体内容，url形式：https://yoursite/文章标题/ -->
<!-- 同时为「标签tag」，「朋友friend」，「分类categories」，「关于about」页面的承载页面，具体展示取决于page.type -->


  <!-- LaTex Display -->

  
    <script async type="text/javascript" src="/plugins/mathjax/tex-chtml.js"></script>
  
  <script>
    MathJax = {
      tex: {
        inlineMath: [['$', '$'], ['\\(', '\\)']]
      }
    }
  </script>





  <!-- clipboard -->

  
    <script async type="text/javascript" src="/plugins/clipboard.min.js"></script>
  
  
<script src="/js/codeCopy.js"></script>







  

  

  

  
  <!-- 文章内容页 url形式：https://yoursite/文章标题/ -->
  <div class="container post-details" id="post-details">
    <div class="post-content">
      <div class="post-title">JUC笔记</div>
      <div class="post-attach">
        <span class="post-pubtime">
          <i class="iconfont icon-updatetime mr-10" title="Update time"></i>
          2021-09-14 09:50:29
        </span>
        
              <span class="post-categories">
                <i class="iconfont icon-bookmark" title="Categories"></i>
                
                <span class="span--category">
                  <a href="/categories/%E5%A4%9A%E7%BA%BF%E7%A8%8B/" title="多线程">
                    <b>#</b> 多线程
                  </a>
                </span>
                
                <span class="span--category">
                  <a href="/categories/%E5%A4%9A%E7%BA%BF%E7%A8%8B/Java/" title="Java">
                    <b>#</b> Java
                  </a>
                </span>
                
                <span class="span--category">
                  <a href="/categories/%E5%A4%9A%E7%BA%BF%E7%A8%8B/Java/%E5%90%8E%E7%AB%AF/" title="后端">
                    <b>#</b> 后端
                  </a>
                </span>
                
                <span class="span--category">
                  <a href="/categories/%E5%A4%9A%E7%BA%BF%E7%A8%8B/Java/%E5%90%8E%E7%AB%AF/Java/" title="Java">
                    <b>#</b> Java
                  </a>
                </span>
                
              </span>
          
              <span class="post-tags">
                <i class="iconfont icon-tags mr-10" title="Tags"></i>
                
                <span class="span--tag mr-8">
                  <a href="/tags/Java/" title="Java">
                    #Java
                  </a>
                </span>
                
                <span class="span--tag mr-8">
                  <a href="/tags/%E5%B7%A5%E5%85%B7/" title="工具">
                    #工具
                  </a>
                </span>
                
                <span class="span--tag mr-8">
                  <a href="/tags/JUC/" title="JUC">
                    #JUC
                  </a>
                </span>
                
                <span class="span--tag mr-8">
                  <a href="/tags/%E5%A4%9A%E7%BA%BF%E7%A8%8B/" title="多线程">
                    #多线程
                  </a>
                </span>
                
              </span>
          
      </div>
      <div class="markdown-body">
        <h2 id="Interface-Lock"><a href="#Interface-Lock" class="headerlink" title="Interface Lock"></a>Interface Lock</h2><blockquote>
<p>All Known Implementing Classes:</p>
<p>ReentrantLock、ReentrantReadWriteLock.ReadLock、ReentrantReadWriteLock.WriteLock</p>
</blockquote>
<p>公平锁：先来后到</p>
<p><strong>非公平锁：可以插队（插队）</strong></p>
<p><img src="http://qiniu.c77544s.top/picgo/202210121454118.png" alt="image-20210914101016223"></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">BoundedBuffer</span> &#123;</span><br><span class="line">   <span class="keyword">final</span> <span class="type">Lock</span> <span class="variable">lock</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ReentrantLock</span>();</span><br><span class="line">   <span class="keyword">final</span> <span class="type">Condition</span> <span class="variable">notFull</span>  <span class="operator">=</span> lock.newCondition(); </span><br><span class="line">   <span class="keyword">final</span> <span class="type">Condition</span> <span class="variable">notEmpty</span> <span class="operator">=</span> lock.newCondition(); </span><br><span class="line"></span><br><span class="line">   <span class="keyword">final</span> Object[] items = <span class="keyword">new</span> <span class="title class_">Object</span>[<span class="number">100</span>];</span><br><span class="line">   <span class="type">int</span> putptr, takeptr, count;</span><br><span class="line"></span><br><span class="line">   <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">put</span><span class="params">(Object x)</span> <span class="keyword">throws</span> InterruptedException &#123;</span><br><span class="line">     lock.lock();</span><br><span class="line">     <span class="keyword">try</span> &#123;</span><br><span class="line">       <span class="keyword">while</span> (count == items.length)</span><br><span class="line">         notFull.await();</span><br><span class="line">       items[putptr] = x;</span><br><span class="line">       <span class="keyword">if</span> (++putptr == items.length) putptr = <span class="number">0</span>;</span><br><span class="line">       ++count;</span><br><span class="line">       notEmpty.signal();</span><br><span class="line">     &#125; <span class="keyword">finally</span> &#123;</span><br><span class="line">       lock.unlock();</span><br><span class="line">     &#125;</span><br><span class="line">   &#125;</span><br><span class="line"></span><br><span class="line">   <span class="keyword">public</span> Object <span class="title function_">take</span><span class="params">()</span> <span class="keyword">throws</span> InterruptedException &#123;</span><br><span class="line">     lock.lock();</span><br><span class="line">     <span class="keyword">try</span> &#123;</span><br><span class="line">       <span class="keyword">while</span> (count == <span class="number">0</span>)</span><br><span class="line">         notEmpty.await();</span><br><span class="line">       <span class="type">Object</span> <span class="variable">x</span> <span class="operator">=</span> items[takeptr];</span><br><span class="line">       <span class="keyword">if</span> (++takeptr == items.length) takeptr = <span class="number">0</span>;</span><br><span class="line">       --count;</span><br><span class="line">       notFull.signal();</span><br><span class="line">       <span class="keyword">return</span> x;</span><br><span class="line">     &#125; <span class="keyword">finally</span> &#123;</span><br><span class="line">       lock.unlock();</span><br><span class="line">     &#125;</span><br><span class="line">   &#125;</span><br><span class="line"> &#125;</span><br></pre></td></tr></table></figure>

<h2 id="8锁现象"><a href="#8锁现象" class="headerlink" title="8锁现象"></a>8锁现象</h2><p>8个关于锁的问题</p>
<p>如何判断锁是谁，锁到底锁的是谁</p>
<p>普通的synchronized方法锁的对象是方法的调用者，也就是调用方法的实例化变量</p>
<p>静态的（static）synchronized方法锁的对象是方法的调用者，也就是类</p>
<h2 id="集合类不安全"><a href="#集合类不安全" class="headerlink" title="集合类不安全"></a>集合类不安全</h2><p><strong>java.util.ConcurrentModificationException</strong>   <strong>并发修改异常</strong></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">List&lt;String&gt; list = <span class="keyword">new</span> <span class="title class_">ArrayList</span>&lt;&gt;();<span class="comment">//并发下ArrayList不安全</span></span><br><span class="line"><span class="keyword">for</span> (<span class="type">int</span> <span class="variable">i</span> <span class="operator">=</span> <span class="number">0</span>; i &lt; <span class="number">10</span>; i++) &#123;</span><br><span class="line">    <span class="keyword">new</span> <span class="title class_">Thread</span>(()-&gt;&#123;</span><br><span class="line">        list.add(UUID.randomUUID().toString().substring(<span class="number">0</span>, <span class="number">5</span>));</span><br><span class="line">        System.out.println(list);</span><br><span class="line">    &#125;, String.valueOf(i)).start();</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>结果：</p>
<figure class="highlight txt"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">[75795]</span><br><span class="line">[75795, 71586, 39235]</span><br><span class="line">[75795, 71586]</span><br><span class="line">[75795]</span><br><span class="line">[75795, 71586, 39235, 6ab3e, af04b]</span><br><span class="line">[75795, 71586, 39235, 6ab3e, af04b, 50f74, 3bef9, 37d5a, 408b2]</span><br><span class="line">[75795, 71586, 39235, 6ab3e]</span><br><span class="line">Exception in thread &quot;5&quot; Exception in thread &quot;1&quot; Exception in thread &quot;6&quot; java.util.ConcurrentModificationException</span><br></pre></td></tr></table></figure>

<p><strong>解决方案1:使用Vector，但是已经过时不使用</strong></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">List&lt;String&gt; list = <span class="keyword">new</span> <span class="title class_">Vector</span>&lt;&gt;();<span class="comment">//Vector是线程安全的</span></span><br></pre></td></tr></table></figure>

<p><strong>解决方案2:</strong></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">List&lt;Object&gt; list = Collections.synchronizedList(<span class="keyword">new</span> <span class="title class_">ArrayList</span>&lt;&gt;());</span><br></pre></td></tr></table></figure>

<p><strong>解决方案3:</strong></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> java.util.concurrent.CopyOnWriteArrayList;</span><br><span class="line"></span><br><span class="line">List&lt;Object&gt; list = <span class="keyword">new</span> <span class="title class_">CopyOnWriteArrayList</span>&lt;&gt;();</span><br></pre></td></tr></table></figure>

<p> <strong>CopyOnWrite写入时复制</strong>，COW，计算机设计领域的一种优化策略</p>
<p>多个线程调用的时候，list，读取的是固定的，写入（覆盖）</p>
<p>在写入的时候避免覆盖，造成数据问题</p>
<p>读写分离</p>
<p><strong>CopyOnWriteArrayList 比 Vector厉害在哪？</strong></p>
<p>Vector使用synchronized性能低，CopyOnWriteArrayList使用ReentrantLock锁性能更高，如下为CopyOnWriteArrayList的add方法</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="type">boolean</span> <span class="title function_">add</span><span class="params">(E e)</span> &#123;</span><br><span class="line">    <span class="keyword">final</span> <span class="type">ReentrantLock</span> <span class="variable">lock</span> <span class="operator">=</span> <span class="built_in">this</span>.lock;</span><br><span class="line">    lock.lock();</span><br><span class="line">    <span class="keyword">try</span> &#123;</span><br><span class="line">        Object[] elements = getArray();</span><br><span class="line">        <span class="type">int</span> <span class="variable">len</span> <span class="operator">=</span> elements.length;</span><br><span class="line">        Object[] newElements = Arrays.copyOf(elements, len + <span class="number">1</span>);<span class="comment">//复制一份</span></span><br><span class="line">        newElements[len] = e;</span><br><span class="line">        setArray(newElements);</span><br><span class="line">        <span class="keyword">return</span> <span class="literal">true</span>;</span><br><span class="line">    &#125; <span class="keyword">finally</span> &#123;</span><br><span class="line">        lock.unlock();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>



<p><strong>Set同理，可以使用CopyOnWriteArraySet</strong></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">private</span> <span class="type">boolean</span> <span class="title function_">addIfAbsent</span><span class="params">(E e, Object[] snapshot)</span> &#123;</span><br><span class="line">    <span class="keyword">final</span> <span class="type">ReentrantLock</span> <span class="variable">lock</span> <span class="operator">=</span> <span class="built_in">this</span>.lock;</span><br><span class="line">    lock.lock();</span><br><span class="line">    <span class="keyword">try</span> &#123;</span><br><span class="line">        Object[] current = getArray();</span><br><span class="line">        <span class="type">int</span> <span class="variable">len</span> <span class="operator">=</span> current.length;</span><br><span class="line">        <span class="keyword">if</span> (snapshot != current) &#123;</span><br><span class="line">            <span class="comment">// Optimize for lost race to another addXXX operation</span></span><br><span class="line">            <span class="type">int</span> <span class="variable">common</span> <span class="operator">=</span> Math.min(snapshot.length, len);</span><br><span class="line">            <span class="keyword">for</span> (<span class="type">int</span> <span class="variable">i</span> <span class="operator">=</span> <span class="number">0</span>; i &lt; common; i++)</span><br><span class="line">                <span class="keyword">if</span> (current[i] != snapshot[i] &amp;&amp; eq(e, current[i]))</span><br><span class="line">                    <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line">            <span class="keyword">if</span> (indexOf(e, current, common, len) &gt;= <span class="number">0</span>)</span><br><span class="line">                    <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        Object[] newElements = Arrays.copyOf(current, len + <span class="number">1</span>);</span><br><span class="line">        newElements[len] = e;</span><br><span class="line">        setArray(newElements);</span><br><span class="line">        <span class="keyword">return</span> <span class="literal">true</span>;</span><br><span class="line">    &#125; <span class="keyword">finally</span> &#123;</span><br><span class="line">        lock.unlock();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p><strong>HashMap可以使用ConcurrentHashMap</strong></p>
<h2 id="Callable"><a href="#Callable" class="headerlink" title="Callable"></a>Callable</h2><p><img src="http://qiniu.c77544s.top/picgo/202210121454707.png" alt="image-20210914120526410"></p>
<p>1、可以有返回值</p>
<p>2、可以有异常</p>
<p>3、方法不同，call()</p>
<p><strong>Callable如何启动</strong></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="number">1.</span> <span class="keyword">new</span> <span class="title class_">Thread</span>(<span class="keyword">new</span> <span class="title class_">Runnable</span>()).start();</span><br><span class="line"><span class="number">2.</span> <span class="keyword">new</span> <span class="title class_">Thread</span>(<span class="keyword">new</span> <span class="title class_">FutureTask</span>&lt;V&gt;()).start();<span class="comment">//FutureTask extends Runnable,所以与第一种等价</span></span><br><span class="line"><span class="number">3.</span> <span class="keyword">new</span> <span class="title class_">Thread</span>(<span class="keyword">new</span> <span class="title class_">FutureTask</span>&lt;V&gt;( Callable )).start();<span class="comment">//传入Callable</span></span><br><span class="line"></span><br><span class="line">futureTask.get();<span class="comment">//可获取线程的返回值， get方法可能会产生阻塞</span></span><br></pre></td></tr></table></figure>

<p><strong>细节</strong></p>
<p>1、有缓存</p>
<p>2、结果可能需要等待，会阻塞</p>
<h2 id="常用辅助类（必会）"><a href="#常用辅助类（必会）" class="headerlink" title="常用辅助类（必会）"></a>常用辅助类（必会）</h2><h3 id="CountDownLatch"><a href="#CountDownLatch" class="headerlink" title="CountDownLatch"></a>CountDownLatch</h3><p><img src="http://qiniu.c77544s.top/picgo/202210121454709.png" alt="image-20210914122508404"></p>
<p><strong>原理：</strong></p>
<p><code>countDownLatch.countDown();</code>&#x2F;&#x2F;数量-1</p>
<p><code>countDownLatch.await();</code>&#x2F;&#x2F;计数器归零</p>
<p>每有一个线程，就将计数器-1，只有计数器变为0时，await方法才会被唤醒，继续执行</p>
<h3 id="CyclicBarrier"><a href="#CyclicBarrier" class="headerlink" title="CyclicBarrier"></a>CyclicBarrier</h3><p><strong>CountDownLatch是减法计数器，CyclicBarrier是加法计数器</strong></p>
<p><img src="http://qiniu.c77544s.top/picgo/202210121454710.png" alt="image-20210914123027943"></p>
<h3 id="Semaphore"><a href="#Semaphore" class="headerlink" title="Semaphore"></a>Semaphore</h3><p>信号量</p>
<p><img src="http://qiniu.c77544s.top/picgo/202210121454711.png" alt="image-20210914123559007"></p>
<p>原理：</p>
<p><code>semaphore.acquire();</code>获得，如果已经满了，等待到释放为止</p>
<p><code>semaphore..release();</code>释放，会将当前的信号量释放+1，然后唤醒等待的线程</p>
<p>作用：多个共享资源的互斥使用！并发限流，控制最大的线程数！</p>
<h2 id="ReadWriteLock锁"><a href="#ReadWriteLock锁" class="headerlink" title="ReadWriteLock锁"></a>ReadWriteLock锁</h2><p><strong>独占锁（写锁）</strong>，一次只能由一个线程占有</p>
<p><strong>共享锁（读锁）</strong>，多个线程可以同时占有</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">ReadWriteLockDemo</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> &#123;</span><br><span class="line">        <span class="type">MyCache</span> <span class="variable">myCache</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">MyCache</span>();</span><br><span class="line">        <span class="keyword">for</span> (<span class="type">int</span> <span class="variable">i</span> <span class="operator">=</span> <span class="number">0</span>; i &lt; <span class="number">5</span>; i++) &#123;</span><br><span class="line">            <span class="keyword">final</span> <span class="type">int</span> <span class="variable">temp</span> <span class="operator">=</span> i;</span><br><span class="line">            <span class="keyword">new</span> <span class="title class_">Thread</span>(() -&gt; myCache.put(temp + <span class="string">&quot;&quot;</span>, temp), String.valueOf(temp)).start();</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">for</span> (<span class="type">int</span> <span class="variable">i</span> <span class="operator">=</span> <span class="number">0</span>; i &lt; <span class="number">5</span>; i++) &#123;</span><br><span class="line">            <span class="keyword">final</span> <span class="type">int</span> <span class="variable">temp</span> <span class="operator">=</span> i;</span><br><span class="line">            <span class="keyword">new</span> <span class="title class_">Thread</span>(() -&gt; myCache.get(temp + <span class="string">&quot;&quot;</span>), String.valueOf(temp)).start();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">MyCache</span> &#123;</span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">volatile</span> Map&lt;String, Object&gt; map = <span class="keyword">new</span> <span class="title class_">HashMap</span>&lt;&gt;();</span><br><span class="line"></span><br><span class="line">    <span class="comment">//读写锁：更加细粒度的控制</span></span><br><span class="line">    <span class="keyword">private</span> <span class="type">ReadWriteLock</span> <span class="variable">readWriteLock</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ReentrantReadWriteLock</span>();</span><br><span class="line"></span><br><span class="line">    <span class="comment">//写入的时候只希望同时只有一个线程写</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">put</span><span class="params">(String key, Object value)</span> &#123;</span><br><span class="line">        readWriteLock.writeLock().lock();</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            System.out.println(Thread.currentThread().getName() + <span class="string">&quot;写入&quot;</span> + key);</span><br><span class="line">            map.put(key, value);</span><br><span class="line">            System.out.println(<span class="string">&quot;写入ok&quot;</span>);</span><br><span class="line">        &#125; <span class="keyword">catch</span> (Exception e) &#123;</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">        &#125; <span class="keyword">finally</span> &#123;</span><br><span class="line">            readWriteLock.writeLock().unlock();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">//读可以多个进程读</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">get</span><span class="params">(String key)</span> &#123;</span><br><span class="line">        readWriteLock.readLock().lock();</span><br><span class="line"></span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            System.out.println(Thread.currentThread().getName() + <span class="string">&quot;读取&quot;</span> + key);</span><br><span class="line">            <span class="type">Object</span> <span class="variable">o</span> <span class="operator">=</span> map.get(key);</span><br><span class="line">            System.out.println(<span class="string">&quot;读取ok&quot;</span>);</span><br><span class="line">        &#125; <span class="keyword">catch</span> (Exception e) &#123;</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">        &#125; <span class="keyword">finally</span> &#123;</span><br><span class="line">            readWriteLock.readLock().unlock();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h2 id="阻塞队列BlockingQueue"><a href="#阻塞队列BlockingQueue" class="headerlink" title="阻塞队列BlockingQueue"></a>阻塞队列BlockingQueue</h2><p><img src="http://qiniu.c77544s.top/picgo/202210121454712.png" alt="image-20210914132752107"></p>
<p><strong>什么情况下使用阻塞队列？多线程、线程池</strong></p>
<h3 id="四组API"><a href="#四组API" class="headerlink" title="四组API"></a>四组API</h3><p><img src="http://qiniu.c77544s.top/picgo/202210121454713.png" alt="image-20210914134127928"></p>
<h3 id="SynchronousQueue同步队列"><a href="#SynchronousQueue同步队列" class="headerlink" title="SynchronousQueue同步队列"></a>SynchronousQueue同步队列</h3><p>没有容量，进去一个元素，必须等待取出来之后，才能往里边存元素</p>
<p>put、take</p>
<h2 id="线程池（重点）"><a href="#线程池（重点）" class="headerlink" title="线程池（重点）"></a>线程池（重点）</h2><p>线程池：三大方法、7大参数、4种拒绝策略</p>
<p><img src="http://qiniu.c77544s.top/picgo/202210121454714.png" alt="image-20210914135622257"></p>
<h3 id="三大方法"><a href="#三大方法" class="headerlink" title="三大方法"></a>三大方法</h3><p><img src="http://qiniu.c77544s.top/picgo/202210121454715.png" alt="image-20210914135502709"></p>
<h3 id="七大参数"><a href="#七大参数" class="headerlink" title="七大参数"></a>七大参数</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">static</span> ExecutorService <span class="title function_">newSingleThreadExecutor</span><span class="params">()</span> &#123;</span><br><span class="line">  <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">FinalizableDelegatedExecutorService</span></span><br><span class="line">    (<span class="keyword">new</span> <span class="title class_">ThreadPoolExecutor</span>(<span class="number">1</span>, <span class="number">1</span>,</span><br><span class="line">                            <span class="number">0L</span>, TimeUnit.MILLISECONDS,</span><br><span class="line">                            <span class="keyword">new</span> <span class="title class_">LinkedBlockingQueue</span>&lt;Runnable&gt;()));</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">static</span> ExecutorService <span class="title function_">newFixedThreadPool</span><span class="params">(<span class="type">int</span> nThreads)</span> &#123;</span><br><span class="line">  <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">ThreadPoolExecutor</span>(nThreads, nThreads,</span><br><span class="line">                                <span class="number">0L</span>, TimeUnit.MILLISECONDS,</span><br><span class="line">                                <span class="keyword">new</span> <span class="title class_">LinkedBlockingQueue</span>&lt;Runnable&gt;());</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">static</span> ExecutorService <span class="title function_">newCachedThreadPool</span><span class="params">()</span> &#123;</span><br><span class="line">  <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">ThreadPoolExecutor</span>(<span class="number">0</span>, Integer.MAX_VALUE, <span class="comment">//0到最大</span></span><br><span class="line">                                <span class="number">60L</span>, TimeUnit.SECONDS,</span><br><span class="line">                                <span class="keyword">new</span> <span class="title class_">SynchronousQueue</span>&lt;Runnable&gt;());</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 使用给定的初始参数创建一个新的ThreadPoolExecutor 。</span></span><br><span class="line"><span class="comment"> * 参数：</span></span><br><span class="line"><span class="comment"> * corePoolSize – 要保留在池中的线程数，即使它们处于空闲状态，除非设置了allowCoreThreadTimeOut</span></span><br><span class="line"><span class="comment"> * maximumPoolSize – 池中允许的最大线程数</span></span><br><span class="line"><span class="comment"> * keepAliveTime – 当线程数大于核心数时，这是多余空闲线程在终止前等待新任务的最长时间。</span></span><br><span class="line"><span class="comment"> * unit – keepAliveTime参数的时间单位</span></span><br><span class="line"><span class="comment"> * workQueue – 用于在执行任务之前保存任务的队列。 这个队列将只保存execute方法提交的Runnable任务。</span></span><br><span class="line"><span class="comment"> * threadFactory – 执行程序创建新线程时使用的工厂</span></span><br><span class="line"><span class="comment"> * handler – 执行被阻塞时使用的处理程序，因为达到了线程边界和队列容量</span></span><br><span class="line"><span class="comment"> */</span> </span><br><span class="line"><span class="keyword">public</span> <span class="title function_">ThreadPoolExecutor</span><span class="params">(<span class="type">int</span> corePoolSize, //核心线程大小</span></span><br><span class="line"><span class="params">                          <span class="type">int</span> maximumPoolSize, //最大核心线程大小</span></span><br><span class="line"><span class="params">                          <span class="type">long</span> keepAliveTime, //超时没人调用就会释放</span></span><br><span class="line"><span class="params">                          TimeUnit unit, //超时单位</span></span><br><span class="line"><span class="params">                          BlockingQueue&lt;Runnable&gt; workQueue, // 阻塞队列</span></span><br><span class="line"><span class="params">                          ThreadFactory threadFactory, //线程工厂，创建线程的</span></span><br><span class="line"><span class="params">                          RejectedExecutionHandler handler)</span> &#123; <span class="comment">// 拒绝策略</span></span><br><span class="line">    <span class="keyword">if</span> (corePoolSize &lt; <span class="number">0</span> ||</span><br><span class="line">        maximumPoolSize &lt;= <span class="number">0</span> ||</span><br><span class="line">        maximumPoolSize &lt; corePoolSize ||</span><br><span class="line">        keepAliveTime &lt; <span class="number">0</span>)</span><br><span class="line">        <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">IllegalArgumentException</span>();</span><br><span class="line">    <span class="keyword">if</span> (workQueue == <span class="literal">null</span> || threadFactory == <span class="literal">null</span> || handler == <span class="literal">null</span>)</span><br><span class="line">        <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">NullPointerException</span>();</span><br><span class="line">    <span class="built_in">this</span>.acc = System.getSecurityManager() == <span class="literal">null</span> ?</span><br><span class="line">            <span class="literal">null</span> :</span><br><span class="line">            AccessController.getContext();</span><br><span class="line">    <span class="built_in">this</span>.corePoolSize = corePoolSize;</span><br><span class="line">    <span class="built_in">this</span>.maximumPoolSize = maximumPoolSize;</span><br><span class="line">    <span class="built_in">this</span>.workQueue = workQueue;</span><br><span class="line">    <span class="built_in">this</span>.keepAliveTime = unit.toNanos(keepAliveTime);</span><br><span class="line">    <span class="built_in">this</span>.threadFactory = threadFactory;</span><br><span class="line">    <span class="built_in">this</span>.handler = handler;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p><img src="http://qiniu.c77544s.top/picgo/202210121454716.png" alt="image-20210914140930465"></p>
<p><strong>既然上面创建线程池的方法不可用，那么怎么创建线程呢？</strong></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//自定义线程池，因为工具类创建线程池不安全</span></span><br><span class="line"><span class="type">ExecutorService</span> <span class="variable">threadPool</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ThreadPoolExecutor</span>(</span><br><span class="line">        <span class="number">2</span>,</span><br><span class="line">        <span class="number">5</span>,</span><br><span class="line">        <span class="number">3</span>,<span class="comment">//除核心线程之外的线程，如果没有使用的话3秒后释放线程</span></span><br><span class="line">        TimeUnit.SECONDS,  </span><br><span class="line">        <span class="keyword">new</span> <span class="title class_">LinkedBlockingQueue</span>&lt;&gt;(<span class="number">3</span>),</span><br><span class="line">        Executors.defaultThreadFactory(),</span><br><span class="line">        <span class="keyword">new</span> <span class="title class_">ThreadPoolExecutor</span>.AbortPolicy());<span class="comment">//（默认拒绝策略）银行满了，还有人进来，就不处理这个人的，并且跑出异常</span></span><br></pre></td></tr></table></figure>

<h3 id="四大拒绝策略"><a href="#四大拒绝策略" class="headerlink" title="四大拒绝策略"></a>四大拒绝策略</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">new</span> <span class="title class_">ThreadPoolExecutor</span>.AbortPolicy();<span class="comment">//（默认拒绝策略）银行满了，还有人进来，就不处理这个人的，并且跑出异常</span></span><br><span class="line"><span class="keyword">new</span> <span class="title class_">ThreadPoolExecutor</span>.CallerRunsPolicy();<span class="comment">// 哪来的去哪里,比如如果是main线程调用线程池，超出后，由main线程处理 </span></span><br><span class="line"><span class="keyword">new</span> <span class="title class_">ThreadPoolExecutor</span>.DiscardPolicy();<span class="comment">// 队列满了不回抛出异常，丢掉任务</span></span><br><span class="line"><span class="keyword">new</span> <span class="title class_">ThreadPoolExecutor</span>.DiscardOldestPolicy();<span class="comment">// 队列满了不回抛出异常，尝试和最早的竞争，竞争失败就丢掉任务</span></span><br></pre></td></tr></table></figure>



<h3 id="最大线程该怎么定义（maximumPoolSize）"><a href="#最大线程该怎么定义（maximumPoolSize）" class="headerlink" title="最大线程该怎么定义（maximumPoolSize）"></a>最大线程该怎么定义（maximumPoolSize）</h3><p>1、CPU密集型, 几核就是几，保证效率最高</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Runtime.getRuntime().availableProcessors()</span><br></pre></td></tr></table></figure>

<p>2、IO密集型，&gt; 判断你程序中十分耗IO的线程</p>
<h2 id="ForkJoin"><a href="#ForkJoin" class="headerlink" title="ForkJoin"></a>ForkJoin</h2><p>ForkJoin 在jdk 1.7中， 并行执行任务，提高效率，大数据量    类似于MapReduce</p>
<blockquote>
<p>ForkJoin特点：工作窃取</p>
</blockquote>
<p>这个里边维护的都是双端队列</p>
<p>1、ForkJoinPool 通过它来执行</p>
<p>2、计算任务 <code>forkJoinPool.execute(ForkJoinTask&lt;?&gt; task);</code></p>
<p>3、 计算类要继承ForkJoinTask</p>
<p><img src="http://qiniu.c77544s.top/picgo/202210121454717.png" alt="image-20210914150111885"></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">ForkJoinDemo</span> <span class="keyword">extends</span> <span class="title class_">RecursiveTask</span>&lt;Long&gt; &#123;</span><br><span class="line">    <span class="keyword">private</span> Long start;</span><br><span class="line">    <span class="keyword">private</span> Long end;</span><br><span class="line"></span><br><span class="line">    <span class="comment">//临界值</span></span><br><span class="line">    <span class="keyword">private</span> <span class="type">Long</span> <span class="variable">temp</span> <span class="operator">=</span> <span class="number">100_0000L</span>;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="title function_">ForkJoinDemo</span><span class="params">(Long start, Long end)</span> &#123;</span><br><span class="line">        <span class="built_in">this</span>.start = start;</span><br><span class="line">        <span class="built_in">this</span>.end = end;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">protected</span> Long <span class="title function_">compute</span><span class="params">()</span> &#123;</span><br><span class="line">        <span class="keyword">if</span> (end - start &gt; temp) &#123; <span class="comment">//forkjoin</span></span><br><span class="line">            <span class="comment">// 分支合并计算</span></span><br><span class="line">            <span class="type">long</span> <span class="variable">middle</span> <span class="operator">=</span> (start + end) / <span class="number">2</span>;</span><br><span class="line">            <span class="type">ForkJoinDemo</span> <span class="variable">task1</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ForkJoinDemo</span>(start, middle);</span><br><span class="line">            <span class="type">ForkJoinDemo</span> <span class="variable">task2</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ForkJoinDemo</span>(middle + <span class="number">1</span>, end);</span><br><span class="line">            task1.fork();<span class="comment">//差分任务，把任务压入线程队列</span></span><br><span class="line">            task2.fork();<span class="comment">//差分任务，把任务压入线程队列</span></span><br><span class="line">            <span class="keyword">return</span> task1.join() + task2.join();</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            <span class="type">long</span> <span class="variable">sum</span> <span class="operator">=</span> <span class="number">0</span>;</span><br><span class="line">            <span class="keyword">for</span> (<span class="type">long</span> <span class="variable">i</span> <span class="operator">=</span> start; i &lt;= end; i++) &#123;</span><br><span class="line">                sum += i;</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">return</span> sum;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> ExecutionException, InterruptedException &#123;</span><br><span class="line">        test1();</span><br><span class="line">        test2();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">test1</span><span class="params">()</span> <span class="keyword">throws</span> ExecutionException, InterruptedException &#123;</span><br><span class="line">        <span class="type">long</span> <span class="variable">startTime</span> <span class="operator">=</span> System.currentTimeMillis();</span><br><span class="line">        <span class="type">ForkJoinPool</span> <span class="variable">forkJoinPool</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ForkJoinPool</span>();</span><br><span class="line">        <span class="type">ForkJoinDemo</span> <span class="variable">task</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ForkJoinDemo</span>(<span class="number">0L</span>, <span class="number">10_0000_0000L</span>);</span><br><span class="line">        <span class="comment">// forkJoinPool.execute(task);</span></span><br><span class="line">        ForkJoinTask&lt;Long&gt; submit = forkJoinPool.submit(task);</span><br><span class="line"></span><br><span class="line">        <span class="type">Long</span> <span class="variable">sum</span> <span class="operator">=</span> submit.get();</span><br><span class="line">        <span class="type">long</span> <span class="variable">endTime</span> <span class="operator">=</span> System.currentTimeMillis();</span><br><span class="line"></span><br><span class="line">        System.out.println(<span class="string">&quot;sum:&quot;</span> + sum + <span class="string">&quot;时间：&quot;</span> + (endTime-startTime));</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">//更快</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">test2</span><span class="params">()</span> <span class="keyword">throws</span> ExecutionException, InterruptedException &#123;</span><br><span class="line">        <span class="type">long</span> <span class="variable">startTime</span> <span class="operator">=</span> System.currentTimeMillis();</span><br><span class="line"></span><br><span class="line">        <span class="comment">// 并行流计算 （）（]</span></span><br><span class="line">        <span class="type">long</span> <span class="variable">sum</span> <span class="operator">=</span> LongStream.rangeClosed(<span class="number">0L</span>, <span class="number">10_0000_0000L</span>).parallel().reduce(<span class="number">0</span>, Long::sum);</span><br><span class="line">        <span class="type">long</span> <span class="variable">endTime</span> <span class="operator">=</span> System.currentTimeMillis();</span><br><span class="line"></span><br><span class="line">        System.out.println(<span class="string">&quot;sum:&quot;</span> + sum + <span class="string">&quot;时间：&quot;</span> + (endTime-startTime));</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>结果：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">sum:500000000500000000时间：539</span><br><span class="line">sum:500000000500000000时间：154</span><br></pre></td></tr></table></figure>



<h2 id="异步回调"><a href="#异步回调" class="headerlink" title="异步回调"></a>异步回调</h2><blockquote>
<p>Future 设计的初衷，对将来的某个时间点结果进行建模</p>
</blockquote>
<img src="http://qiniu.c77544s.top/picgo/202210121454718.png" alt="image-20210914152652025" style="zoom:70%;"/>

<p>&#x2F;&#x2F;异步执行</p>
<p>&#x2F;&#x2F;成功回调</p>
<p>&#x2F;&#x2F;失败回调</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> InterruptedException, ExecutionException &#123;</span><br><span class="line">    <span class="comment">// 发起请求,runAsync没有返回值的异步回调</span></span><br><span class="line">    CompletableFuture&lt;Void&gt; completableFuture = CompletableFuture.runAsync(()-&gt;&#123;</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            TimeUnit.SECONDS.sleep(<span class="number">2</span>);</span><br><span class="line">        &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">        &#125;</span><br><span class="line">        System.out.println(Thread.currentThread().getName()+<span class="string">&quot;runAsync=&gt;Void&quot;</span>);</span><br><span class="line">    &#125;);</span><br><span class="line"></span><br><span class="line">    <span class="comment">//supplyAsync有返回结果的异步回调</span></span><br><span class="line">    CompletableFuture&lt;Integer&gt; completableFuture2 = CompletableFuture.supplyAsync(()-&gt; &#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;completableFuture2&quot;</span>);</span><br><span class="line">        <span class="type">int</span> <span class="variable">i</span> <span class="operator">=</span> <span class="number">10</span>/<span class="number">0</span>;</span><br><span class="line">        <span class="keyword">return</span> <span class="number">12</span>;</span><br><span class="line">    &#125;);</span><br><span class="line">    <span class="comment">// System.out.println(completableFuture2.get());//获取completableFuture2的值，会阻塞</span></span><br><span class="line">    <span class="comment">// System.out.println(completableFuture.get());//获取completableFuture的值，会阻塞</span></span><br><span class="line"></span><br><span class="line">    System.out.println(completableFuture2.whenComplete((t, u) -&gt; &#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;t=&gt;&quot;</span> + t);<span class="comment">// 正常的返回结果</span></span><br><span class="line">        System.out.println(<span class="string">&quot;u=&gt;&quot;</span> + u);<span class="comment">// 错误信息 java.util.concurrent.CompletionException: java.lang.ArithmeticException: / by zero</span></span><br><span class="line">    &#125;).exceptionally(throwable -&gt; &#123; <span class="comment">// 处理异常</span></span><br><span class="line">        System.out.println(throwable.getMessage());</span><br><span class="line">        <span class="keyword">return</span> <span class="number">500</span>;</span><br><span class="line">    &#125;).get());</span><br><span class="line"></span><br><span class="line">    Thread.sleep(<span class="number">10000</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h2 id="JMM"><a href="#JMM" class="headerlink" title="JMM"></a>JMM</h2><p><strong>什么是JMM</strong></p>
<p>java内存模型</p>
<p>关于JMM的一些约定：</p>
<p>1、线程解锁前，必须把共享变量立刻刷回主存</p>
<p>2、线程加锁前，必须读取主存中的最新值到工作内存中</p>
<p>3、加锁和解锁是同一把锁</p>
<img src="http://qiniu.c77544s.top/picgo/202210121454719.png" alt="image-20210914165252630" style="zoom:50%;" />

<img src="http://qiniu.c77544s.top/picgo/202210121454720.png" alt="image-20210914165402592" style="zoom:50%;" />

<h2 id="Volatile关键字"><a href="#Volatile关键字" class="headerlink" title="Volatile关键字"></a>Volatile关键字</h2><p>什么是Volatile？java虚拟机提供的<strong>轻量级同步机制</strong></p>
<p>1、保证可见性e</p>
<p><strong>2、不保证原子性</strong></p>
<p>如果不加lock或synchronized，怎样保证原子性？见下一节，比锁高效很多</p>
<blockquote>
<p>使用原子类进行原子操作 </p>
</blockquote>
<p><strong>num++ 不是一个原子性操作</strong>，num++操作步骤是啥?</p>
<ul>
<li>获得这个值</li>
<li>+1 </li>
<li>写回这个值</li>
</ul>
<p>3、禁止指令重排</p>
<blockquote>
<p>什么是指令重排</p>
</blockquote>
<p>源代码—&gt;编译器优化可能重排—&gt;指令并行也可能重排—&gt;内存系统也会重排—&gt;执行</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">int</span> x=<span class="number">1</span>;<span class="comment">//1</span></span><br><span class="line"><span class="type">int</span> y=<span class="number">2</span>;<span class="comment">//2</span></span><br><span class="line">x=x+<span class="number">5</span>;<span class="comment">//3</span></span><br><span class="line">y=x*x;<span class="comment">//4</span></span><br><span class="line"></span><br><span class="line">我们期望：<span class="number">1234</span> ， 但是<span class="number">2134</span>也是对的，<span class="number">1324</span>也是对的，但是<span class="number">4123</span>不对，因为<span class="number">4</span>依赖于<span class="number">1</span></span><br></pre></td></tr></table></figure>

<p>可能造成的结果</p>
<img src="http://qiniu.c77544s.top/picgo/202210121454721.png" alt="image-20210914172349897" style="zoom:50%;" />

<blockquote>
<p> Volatile如何避免内存重排</p>
</blockquote>
<img src="http://qiniu.c77544s.top/picgo/202210121454722.png" alt="image-20210914172549903" style="zoom:50%;" />



<h2 id="原子类"><a href="#原子类" class="headerlink" title="原子类"></a>原子类</h2><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">volatile</span> <span class="type">AtomicInteger</span> <span class="variable">num</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">AtomicInteger</span>(<span class="number">0</span>);</span><br><span class="line">num.getAndIncrement();<span class="comment">//AtomicInteger + 1 方法，CAS操作</span></span><br></pre></td></tr></table></figure>

<p>getAndIncrement如何实现的？</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">final</span> <span class="type">int</span> <span class="title function_">getAndIncrement</span><span class="params">()</span> &#123;</span><br><span class="line">    <span class="keyword">return</span> unsafe.getAndAddInt(<span class="built_in">this</span>, valueOffset, <span class="number">1</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">final</span> <span class="type">int</span> <span class="title function_">getAndAddInt</span><span class="params">(Object o, <span class="type">long</span> offset, <span class="type">int</span> delta)</span> &#123;</span><br><span class="line">    <span class="type">int</span> v;</span><br><span class="line">    <span class="keyword">do</span> &#123;</span><br><span class="line">        v = getIntVolatile(o, offset);</span><br><span class="line">    &#125; <span class="keyword">while</span> (!compareAndSwapInt(o, offset, v, v + delta));</span><br><span class="line">    <span class="keyword">return</span> v;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>底层和操作系统挂钩！在操作系统中修改值！Unsafe是个很特殊的存在</p>
<h2 id="深入理解CAS"><a href="#深入理解CAS" class="headerlink" title="深入理解CAS"></a>深入理解CAS</h2><blockquote>
<p>什么是CAS</p>
</blockquote>
<p><strong>CAS：compareAndSet 的缩写</strong></p>
<p><a target="_blank" rel="noopener" href="https://github.com/CoderLeixiaoshuai/java-eight-part/blob/master/docs/java/juc/%E9%9D%A2%E8%AF%95%E5%BF%85%E9%97%AE%E7%9A%84CAS%E5%8E%9F%E7%90%86%E4%BD%A0%E4%BC%9A%E4%BA%86%E5%90%97.md">详情见GitHub上的八股文</a></p>
<img src="http://qiniu.c77544s.top/picgo/202210121454723.png" alt="image-20210914175225956" style="zoom:50%;" />

<p>CAS：比较当前工作内存中的值和主内存中的值，如果这个值是期望的，那么则执行操作，否则一直循环（自旋锁），直到是期望的值</p>
<p>缺点：</p>
<p>1、循环会耗时</p>
<p>2、一次性只能保证一个共享变量的原子性</p>
<p>3、ABA问题</p>
<blockquote>
<p>CAS :  ABA问题（狸猫换太子）</p>
</blockquote>
<img src="http://qiniu.c77544s.top/picgo/202210121454724.png" alt="image-20210914175739576" style="zoom:80%;" />

<p>右边的线程，将1换成3，又将3换成1，而左边的线程不知道，看还是1。</p>
<p>这个是我们不期望的，我们期望，不能让别人动</p>
<h2 id="原子引用"><a href="#原子引用" class="headerlink" title="原子引用"></a>原子引用</h2><p>待版本号的原子操作</p>
<p>类似于我们平时sql里边的乐观锁</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">AtomicStampedReference&lt;T&gt; xx = <span class="keyword">new</span> <span class="title class_">AtomicStampedReference</span>&lt;&gt;(<span class="number">1</span>, <span class="number">1</span>);<span class="comment">//第一个参数initialRef（期望值）,第二个参数initialStamp（乐观锁的标志）</span></span><br></pre></td></tr></table></figure>



<h2 id="各种锁的理解"><a href="#各种锁的理解" class="headerlink" title="各种锁的理解"></a>各种锁的理解</h2><h3 id="公平锁、非公平锁"><a href="#公平锁、非公平锁" class="headerlink" title="公平锁、非公平锁"></a>公平锁、非公平锁</h3><p>公平锁：先来后到</p>
<p><strong>非公平锁：可以插队（插队）</strong>（默认）</p>
<h3 id="可重入锁"><a href="#可重入锁" class="headerlink" title="可重入锁"></a>可重入锁</h3><p>可重入锁（递归锁）</p>
<img src="http://qiniu.c77544s.top/picgo/202210121454725.png" alt="image-20210914181528815" style="zoom:50%;" />



<h3 id="自旋锁"><a href="#自旋锁" class="headerlink" title="自旋锁"></a>自旋锁</h3><p>Spinlock</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">final</span> <span class="type">int</span> <span class="title function_">getAndAddInt</span><span class="params">(Object o, <span class="type">long</span> offset, <span class="type">int</span> delta)</span> &#123;</span><br><span class="line">    <span class="type">int</span> v;</span><br><span class="line">    <span class="keyword">do</span> &#123;</span><br><span class="line">        v = getIntVolatile(o, offset);</span><br><span class="line">    &#125; <span class="keyword">while</span> (!compareAndSwapInt(o, offset, v, v + delta));</span><br><span class="line">    <span class="keyword">return</span> v;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h3 id="死锁"><a href="#死锁" class="headerlink" title="死锁"></a>死锁</h3><p>1、使用<code>jps -l</code> 定位进程号(jdk bin目录下)</p>
<img src="http://qiniu.c77544s.top/picgo/202210121454726.png" alt="image-20210914182634792" style="zoom:50%;" />

<p>2、使用<code>jstack 进程号</code>找到死锁问题</p>
<img src="http://qiniu.c77544s.top/picgo/202210121454727.png" alt="image-20210914182803167" style="zoom:50%;" />

<p>工作中排查问题：</p>
<p>1、日志</p>
<p>2、堆栈信息</p>

      </div>
      
        <div class="prev-or-next">
          <div class="post-foot-next">
            
              <a href="/2021/09/13/%E5%90%8E%E7%AB%AF/Java/%E5%A4%9A%E7%BA%BF%E7%A8%8B1/" target="_self">
                <i class="iconfont icon-chevronleft"></i>
                <span>Prev</span>
              </a>
            
          </div>
          <div class="post-attach">
            <span class="post-pubtime">
              <i class="iconfont icon-updatetime mr-10" title="Update time"></i>
              2021-09-14 09:50:29
            </span>
            
                  <span class="post-categories">
                    <i class="iconfont icon-bookmark" title="Categories"></i>
                    
                    <span class="span--category">
                      <a href="/categories/%E5%A4%9A%E7%BA%BF%E7%A8%8B/" title="多线程">
                        <b>#</b> 多线程
                      </a>
                    </span>
                    
                    <span class="span--category">
                      <a href="/categories/%E5%A4%9A%E7%BA%BF%E7%A8%8B/Java/" title="Java">
                        <b>#</b> Java
                      </a>
                    </span>
                    
                    <span class="span--category">
                      <a href="/categories/%E5%A4%9A%E7%BA%BF%E7%A8%8B/Java/%E5%90%8E%E7%AB%AF/" title="后端">
                        <b>#</b> 后端
                      </a>
                    </span>
                    
                    <span class="span--category">
                      <a href="/categories/%E5%A4%9A%E7%BA%BF%E7%A8%8B/Java/%E5%90%8E%E7%AB%AF/Java/" title="Java">
                        <b>#</b> Java
                      </a>
                    </span>
                    
                  </span>
              
                  <span class="post-tags">
                    <i class="iconfont icon-tags mr-10" title="Tags"></i>
                    
                    <span class="span--tag mr-8">
                      <a href="/tags/Java/" title="Java">
                        #Java
                      </a>
                    </span>
                    
                    <span class="span--tag mr-8">
                      <a href="/tags/%E5%B7%A5%E5%85%B7/" title="工具">
                        #工具
                      </a>
                    </span>
                    
                    <span class="span--tag mr-8">
                      <a href="/tags/JUC/" title="JUC">
                        #JUC
                      </a>
                    </span>
                    
                    <span class="span--tag mr-8">
                      <a href="/tags/%E5%A4%9A%E7%BA%BF%E7%A8%8B/" title="多线程">
                        #多线程
                      </a>
                    </span>
                    
                  </span>
              
          </div>
          <div class="post-foot-prev">
            
              <a href="/2021/09/16/%E5%90%8E%E7%AB%AF/Java/synchronized-%E7%9A%84%E9%94%81%E5%8D%87%E7%BA%A7%E6%9C%BA%E5%88%B6/" target="_self">
                <span>Next</span>
                <i class="iconfont icon-chevronright"></i>
              </a>
            
          </div>
        </div>
      
    </div>
    
  <div id="btn-catalog" class="btn-catalog">
    <i class="iconfont icon-catalog"></i>
  </div>
  <div class="post-catalog hidden" id="catalog">
    <div class="title">Contents</div>
    <div class="catalog-content">
      
        <ol class="toc"><li class="toc-item toc-level-2"><a class="toc-link" href="#Interface-Lock"><span class="toc-text">Interface Lock</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#8%E9%94%81%E7%8E%B0%E8%B1%A1"><span class="toc-text">8锁现象</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E9%9B%86%E5%90%88%E7%B1%BB%E4%B8%8D%E5%AE%89%E5%85%A8"><span class="toc-text">集合类不安全</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#Callable"><span class="toc-text">Callable</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E5%B8%B8%E7%94%A8%E8%BE%85%E5%8A%A9%E7%B1%BB%EF%BC%88%E5%BF%85%E4%BC%9A%EF%BC%89"><span class="toc-text">常用辅助类（必会）</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#CountDownLatch"><span class="toc-text">CountDownLatch</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#CyclicBarrier"><span class="toc-text">CyclicBarrier</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#Semaphore"><span class="toc-text">Semaphore</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#ReadWriteLock%E9%94%81"><span class="toc-text">ReadWriteLock锁</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E9%98%BB%E5%A1%9E%E9%98%9F%E5%88%97BlockingQueue"><span class="toc-text">阻塞队列BlockingQueue</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#%E5%9B%9B%E7%BB%84API"><span class="toc-text">四组API</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#SynchronousQueue%E5%90%8C%E6%AD%A5%E9%98%9F%E5%88%97"><span class="toc-text">SynchronousQueue同步队列</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E7%BA%BF%E7%A8%8B%E6%B1%A0%EF%BC%88%E9%87%8D%E7%82%B9%EF%BC%89"><span class="toc-text">线程池（重点）</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#%E4%B8%89%E5%A4%A7%E6%96%B9%E6%B3%95"><span class="toc-text">三大方法</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E4%B8%83%E5%A4%A7%E5%8F%82%E6%95%B0"><span class="toc-text">七大参数</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E5%9B%9B%E5%A4%A7%E6%8B%92%E7%BB%9D%E7%AD%96%E7%95%A5"><span class="toc-text">四大拒绝策略</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E6%9C%80%E5%A4%A7%E7%BA%BF%E7%A8%8B%E8%AF%A5%E6%80%8E%E4%B9%88%E5%AE%9A%E4%B9%89%EF%BC%88maximumPoolSize%EF%BC%89"><span class="toc-text">最大线程该怎么定义（maximumPoolSize）</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#ForkJoin"><span class="toc-text">ForkJoin</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E5%BC%82%E6%AD%A5%E5%9B%9E%E8%B0%83"><span class="toc-text">异步回调</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#JMM"><span class="toc-text">JMM</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#Volatile%E5%85%B3%E9%94%AE%E5%AD%97"><span class="toc-text">Volatile关键字</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E5%8E%9F%E5%AD%90%E7%B1%BB"><span class="toc-text">原子类</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E6%B7%B1%E5%85%A5%E7%90%86%E8%A7%A3CAS"><span class="toc-text">深入理解CAS</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E5%8E%9F%E5%AD%90%E5%BC%95%E7%94%A8"><span class="toc-text">原子引用</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E5%90%84%E7%A7%8D%E9%94%81%E7%9A%84%E7%90%86%E8%A7%A3"><span class="toc-text">各种锁的理解</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#%E5%85%AC%E5%B9%B3%E9%94%81%E3%80%81%E9%9D%9E%E5%85%AC%E5%B9%B3%E9%94%81"><span class="toc-text">公平锁、非公平锁</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E5%8F%AF%E9%87%8D%E5%85%A5%E9%94%81"><span class="toc-text">可重入锁</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E8%87%AA%E6%97%8B%E9%94%81"><span class="toc-text">自旋锁</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E6%AD%BB%E9%94%81"><span class="toc-text">死锁</span></a></li></ol></li></ol>
      
    </div>
  </div>

  
<script src="/js/catalog.js"></script>




    
      <div class="comments-container">
        




  
    <script async type="text/javascript" src="/plugins/valine.min.js" onload="loadValineSuc(this)"></script>
  

  <div id="vcomments"></div>

  <script>
    function loadValineSuc() {
      new Valine({
        el: '#vcomments',
        appId: 'H2QqshKF8elT2Si5bfKynT9h-9Nh9j0Va',
        appKey: 'WgtVppOWkTZ8fWNReNI1Ymf7',
        placeholder: '有问题请留言吧!',
        avatar: 'retro',
        lang: 'en'
      })
    }
  </script>

    <style>
      .comments-container .v .vempty {
        display: none!important;
      }
    </style>




      </div>
    
  </div>


        
<div class="footer">
  <div class="social">
    <ul>
      
        <li>
          <a title="github" target="_blank" rel="noopener" href="https://github.com/zchengsite/hexo-theme-oranges">
            <i class="iconfont icon-github"></i>
          </a>
        </li>
      
        <li>
          <a title="email" target="_blank" rel="noopener" href="https://c77544s.github.io/about/">
            <i class="iconfont icon-envelope"></i>
          </a>
        </li>
      
        <li>
          <a title="wechat" target="_blank" rel="noopener" href="https://c77544s.github.io/about/">
            <i class="iconfont icon-wechat"></i>
          </a>
        </li>
      
        <li>
          <a title="rss" href="/atom.xml">
            <i class="iconfont icon-rss"></i>
          </a>
        </li>
      
    </ul>
  </div>
  
    
    <div class="footer-more">
      
        <a target="_blank" rel="noopener" href="https://github.com/zchengsite/hexo-theme-oranges">Copyright © 2023 Oranges</a>
        
    </div>
  
    
    <div class="footer-more">
      
        <a target="_blank" rel="noopener" href="https://github.com/zchengsite/hexo-theme-oranges">Theme by Oranges | Powered by Hexo</a>
        
    </div>
  
  
</div>

      </div>

      <div class="tools-bar">
        <div class="back-to-top tools-bar-item hidden">
  <a href="javascript: void(0)">
    <i class="iconfont icon-chevronup"></i>
  </a>
</div>


<script src="/js/backtotop.js"></script>



        
  <div class="search-icon tools-bar-item" id="search-icon">
    <a href="javascript: void(0)">
      <i class="iconfont icon-search"></i>
    </a>
  </div>

  <div class="search-overlay hidden">
    <div class="search-content" tabindex="0">
      <div class="search-title">
        <span class="search-icon-input">
          <a href="javascript: void(0)">
            <i class="iconfont icon-search"></i>
          </a>
        </span>
        
          <input type="text" class="search-input" id="search-input" placeholder="搜索...">
        
        <span class="search-close-icon" id="search-close-icon">
          <a href="javascript: void(0)">
            <i class="iconfont icon-close"></i>
          </a>
        </span>
      </div>
      <div class="search-result" id="search-result"></div>
    </div>
  </div>

  <script type="text/javascript">
    var inputArea = document.querySelector("#search-input")
    var searchOverlayArea = document.querySelector(".search-overlay")

    inputArea.onclick = function() {
      getSearchFile()
      this.onclick = null
    }

    inputArea.onkeydown = function() {
      if(event.keyCode == 13)
        return false
    }

    function openOrHideSearchContent() {
      let isHidden = searchOverlayArea.classList.contains('hidden')
      if (isHidden) {
        searchOverlayArea.classList.remove('hidden')
        document.body.classList.add('hidden')
        // inputArea.focus()
      } else {
        searchOverlayArea.classList.add('hidden')
        document.body.classList.remove('hidden')
      }
    }

    function blurSearchContent(e) {
      if (e.target === searchOverlayArea) {
        openOrHideSearchContent()
      }
    }

    document.querySelector("#search-icon").addEventListener("click", openOrHideSearchContent, false)
    document.querySelector("#search-close-icon").addEventListener("click", openOrHideSearchContent, false)
    searchOverlayArea.addEventListener("click", blurSearchContent, false)

    var searchFunc = function (path, search_id, content_id) {
      'use strict';
      var $input = document.getElementById(search_id);
      var $resultContent = document.getElementById(content_id);
      $resultContent.innerHTML = "<ul><span class='local-search-empty'>First search, index file loading, please wait...<span></ul>";
      $.ajax({
        // 0x01. load xml file
        url: path,
        dataType: "xml",
        success: function (xmlResponse) {
          // 0x02. parse xml file
          var datas = $("entry", xmlResponse).map(function () {
            return {
              title: $("title", this).text(),
              content: $("content", this).text(),
              url: $("url", this).text()
            };
          }).get();
          $resultContent.innerHTML = "";

          $input.addEventListener('input', function () {
            // 0x03. parse query to keywords list
            var str = '<ul class=\"search-result-list\">';
            var keywords = this.value.trim().toLowerCase().split(/[\s\-]+/);
            $resultContent.innerHTML = "";
            if (this.value.trim().length <= 0) {
              return;
            }
            // 0x04. perform local searching
            datas.forEach(function (data) {
              var isMatch = true;
              var content_index = [];
              if (!data.title || data.title.trim() === '') {
                data.title = "Untitled";
              }
              var orig_data_title = data.title.trim();
              var data_title = orig_data_title.toLowerCase();
              var orig_data_content = data.content.trim().replace(/<[^>]+>/g, "");
              var data_content = orig_data_content.toLowerCase();
              var data_url = data.url;
              var index_title = -1;
              var index_content = -1;
              var first_occur = -1;
              // only match artiles with not empty contents
              if (data_content !== '') {
                keywords.forEach(function (keyword, i) {
                  index_title = data_title.indexOf(keyword);
                  index_content = data_content.indexOf(keyword);

                  if (index_title < 0 && index_content < 0) {
                    isMatch = false;
                  } else {
                    if (index_content < 0) {
                      index_content = 0;
                    }
                    if (i == 0) {
                      first_occur = index_content;
                    }
                    // content_index.push({index_content:index_content, keyword_len:keyword_len});
                  }
                });
              } else {
                isMatch = false;
              }
              // 0x05. show search results
              if (isMatch) {
                str += "<li><a href='" + data_url + "' class='search-result-title'>" + orig_data_title + "</a>";
                var content = orig_data_content;
                if (first_occur >= 0) {
                  // cut out 100 characters
                  var start = first_occur - 20;
                  var end = first_occur + 80;

                  if (start < 0) {
                    start = 0;
                  }

                  if (start == 0) {
                    end = 100;
                  }

                  if (end > content.length) {
                    end = content.length;
                  }

                  var match_content = content.substr(start, end);

                  // highlight all keywords
                  keywords.forEach(function (keyword) {
                    var regS = new RegExp(keyword, "gi");
                    match_content = match_content.replace(regS, "<span class=\"search-keyword\">" + keyword + "</span>");
                  });

                  str += "<p class=\"search-result-abstract\">" + match_content + "...</p>"
                }
                str += "</li>";
              }
            });
            str += "</ul>";
            if (str.indexOf('<li>') === -1) {
              return $resultContent.innerHTML = "<ul><span class='local-search-empty'>No result<span></ul>";
            }
            $resultContent.innerHTML = str;
          });
        },
        error: function(xhr, status, error) {
          $resultContent.innerHTML = ""
          if (xhr.status === 404) {
            $resultContent.innerHTML = "<ul><span class='local-search-empty'>The search.xml file was not found, please refer to：<a href='https://github.com/zchengsite/hexo-theme-oranges#configuration' target='_black'>configuration</a><span></ul>";
          } else {
            $resultContent.innerHTML = "<ul><span class='local-search-empty'>The request failed, Try to refresh the page or try again later.<span></ul>";
          }
        }
      });
      $(document).on('click', '#search-close-icon', function() {
        $('#search-input').val('');
        $('#search-result').html('');
      });
    }

    var getSearchFile = function() {
        var path = "/search.xml";
        searchFunc(path, 'search-input', 'search-result');
    }
  </script>




        
  <div class="tools-bar-item theme-icon" id="switch-color-scheme">
    <a href="javascript: void(0)">
      <i id="theme-icon" class="iconfont icon-moon"></i>
    </a>
  </div>

  
<script src="/js/colorscheme.js"></script>





        
  
    <div class="share-icon tools-bar-item">
      <a href="javascript: void(0)" id="share-icon">
        <i class="iconfont iconshare"></i>
      </a>
      <div class="share-content hidden">
        
          <a class="share-item" href="https://twitter.com/intent/tweet?text=' + JUC%E7%AC%94%E8%AE%B0 + '&url=' + http%3A%2F%2Fc77544s.gitee.io%2F2021%2F09%2F14%2F%25E5%2590%258E%25E7%25AB%25AF%2FJava%2FJUC%25E7%25AC%2594%25E8%25AE%25B0%2F + '" target="_blank" title="Twitter">
            <i class="iconfont icon-twitter"></i>
          </a>
        
        
          <a class="share-item" href="https://www.facebook.com/sharer.php?u=http://c77544s.gitee.io/2021/09/14/%E5%90%8E%E7%AB%AF/Java/JUC%E7%AC%94%E8%AE%B0/" target="_blank" title="Facebook">
            <i class="iconfont icon-facebooksquare"></i>
          </a>
        
      </div>
    </div>
  
  
<script src="/js/shares.js"></script>



      </div>
    </div>
  </body>
</html>
